﻿using AliIotAmqpWorker.Common;
using AliIotLib;
using IServices;
using MongoDB.Driver;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using YL.Core.Entity;

namespace AliIotAmqpWorker
{
    public class DeviceStatusTask : BaseTaskProvider
    {
        private readonly IMeter_DeviceStatusHistoryServices deviceStatusHistoryServices;
        private readonly IMeter_DeviceInfoServices deviceInfoServices;
        private readonly IMeter_DeviceStatusServices deviceStatusServices;
        private readonly IIotDeviceManager AliIotDeviceManager;
        private readonly MongoDBHelper _mongoDBHelper;
        private MongoDbTag mongoDbTimeTag;
        private DateTime lastDatetime = DateTime.Now;
        private string dataworkerKey = "raw_status";

        public DeviceStatusTask(IMeter_DeviceStatusHistoryServices DeviceStatusHistoryServices,
                                IMeter_DeviceInfoServices DeviceInfoServices,
                                IMeter_DeviceStatusServices DeviceStatusServices,
                                IIotDeviceManager iotDeviceManager,
                                MongoDBHelper mongoDBHelper)
        {
            deviceStatusHistoryServices = DeviceStatusHistoryServices;
            deviceInfoServices = DeviceInfoServices;
            deviceStatusServices = DeviceStatusServices;
            AliIotDeviceManager = iotDeviceManager;
            _mongoDBHelper = mongoDBHelper;
        }
        
        /// <summary>
        /// 启动任务
        /// </summary>
        public void StartTask()
        {
            //thread = new Thread(TaskCycleHandle);
            //thread.Start();
        }
        /// <summary>
        /// 加载初始化时间参数
        /// </summary>
        private void LoadInitialTime()
        {
            var filterBuilder = Builders<MongoDbTag>.Filter;
            var filter = filterBuilder.And(filterBuilder.Eq(x => x.device_name, GlobalSetting.ClientCode),
                                           filterBuilder.Eq(x => x.value, dataworkerKey));
            var list = _mongoDBHelper.GetList<MongoDbTag>(GlobalSetting.MongoDbTime, filter);
            if (list != null && list.Count > 0)
            {
                mongoDbTimeTag = list[0];
                lastDatetime = mongoDbTimeTag.ts;
            }
            else
            {
                mongoDbTimeTag = new MongoDbTag();
                mongoDbTimeTag.device_name = GlobalSetting.ClientCode;
                mongoDbTimeTag.value = dataworkerKey;
                _mongoDBHelper.InsertOne<MongoDbTag>(mongoDbTimeTag, GlobalSetting.MongoDbTime);
                list = _mongoDBHelper.GetList<MongoDbTag>(GlobalSetting.MongoDbTime, filter);
                if (list != null && list.Count > 0)
                {
                    mongoDbTimeTag = list[0];
                }
            }
        }
        /// <summary>
        /// 任务周期循环处理
        /// </summary>
        public override void TaskCycleHandle()
        {
            DateTime dateTimeNow = DateTime.Now;
            AliIotDeviceStatus deviceStatus;
            Thread.Sleep(1000);
            LoadInitialTime();//加载初始化时间参数
            while (true)
            {
                dateTimeNow = DateTime.Now;
                var filterBuilder = Builders<MongoDbTag>.Filter;
                var filter = filterBuilder.And(filterBuilder.Gt(x => x.ts, lastDatetime),
                                               filterBuilder.Lte(x => x.ts, dateTimeNow));
                var list = _mongoDBHelper.GetList<MongoDbTag>(dataworkerKey, filter);

                if (list != null && list.Count > 0)
                {
                    List<MongoDbTag> Tags = list.OrderBy(x => x.ts).ToList();
                    lastDatetime = Tags[Tags.Count - 1].ts;//获取最新时间
                    foreach (var item in Tags)
                    {
                        deviceStatus = Newtonsoft.Json.JsonConvert.DeserializeObject<AliIotDeviceStatus>(item.value.ToString());
                        if (deviceStatus != null)
                        {
                            DeviceInfo device = deviceInfoServices.QueryableToEntity(x => x.AliDeviceName == deviceStatus.deviceName);
                            if (device != null)
                            {
                                bool status = deviceStatus.status == "online" ? true : false;
                                UpdateDeviceStatus(device, deviceStatus, status);
                            }
                        }
                    }
                    Tags.Clear();
                    Tags = null;
                }
                filterBuilder = Builders<MongoDbTag>.Filter;
                filter = filterBuilder.Lte(x => x.ts, dateTimeNow.AddDays(-7));//删除一周以前数据
                int count = _mongoDBHelper.DeleteMany(dataworkerKey, filter);
                UpdateCycleTime();
                list.Clear();
                list = null;
                StatusCheck();//离线状态检查

                Thread.Sleep(5000);
            }
        }
        /// <summary>
        /// 状态检查。如果设备当前状态为离线，则抽取数据表中的时间，监测是否在线
        /// </summary>
        private void StatusCheck()
        {
            var statusList = deviceStatusServices.QueryableToList(x => x.Status == false);
            foreach (var item in statusList)
            {
                DeviceInfo device = deviceInfoServices.QueryableToEntity(x => x.DeviceId == item.DeviceId);
                if (device != null)
                {
                    AliIotDeviceDetail aliIotDeviceDetail = AliIotDeviceManager.QueryDeviceDetail(device.AliDeviceName);
                    if (aliIotDeviceDetail != null)
                    {
                        if (aliIotDeviceDetail.Status.ToLower() == "online")
                        {
                            item.Status = true;
                            UpdateDeviceStatus(device, null, true);
                        }
                    }
                }
                else
                {
                    deviceStatusServices.Delete(x => x.DeviceId == item.DeviceId);//设备已经不存在，状态表记录删除
                }
            }
        }
        /// <summary>
        /// 更新设备当前状态
        /// </summary>
        /// <param name="device_code"></param>
        /// <param name="status"></param>
        public void UpdateDeviceStatus(DeviceInfo device, AliIotDeviceStatus deviceStatus, bool status)
        {
            DeviceStatus devStatus = deviceStatusServices.QueryableToEntity(x => x.DeviceId == device.DeviceId);
            if (devStatus != null)
            {
                devStatus.ClientIp = deviceStatus==null ? "" : deviceStatus.clientIp;
                devStatus.LastTime = DateTime.Now;
                devStatus.Status = status;
                deviceStatusServices.UpdateEntity(devStatus);
            }
            else
            {
                devStatus = new DeviceStatus();
                devStatus.Status = status;
                devStatus.DeviceId = device.DeviceId;
                devStatus.ClientIp = deviceStatus == null ? "" : deviceStatus.clientIp;
                devStatus.LastTime = DateTime.Now;
                deviceStatusServices.Insert(devStatus);
            }
            DeviceStatusHistory deviceStatusHistory = new DeviceStatusHistory();
            deviceStatusHistory.ClientIp = deviceStatus.clientIp;
            deviceStatusHistory.CreateDate = DateTime.Now;
            deviceStatusHistory.DeviceId = device.DeviceId;
            deviceStatusHistory.Status = status;
            deviceStatusHistoryServices.Insert(deviceStatusHistory);
        }
        /// <summary>
        /// 程序退出，存储最新时间记录
        /// </summary>
        public override void Dispose()
        {
            base.Dispose();
            UpdateCycleTime();
        }

        /// <summary>
        /// 更新存储时间
        /// </summary>
        public void UpdateCycleTime()
        {
            var filterBuilder = Builders<MongoDbTag>.Filter;
            var filter = filterBuilder.And(filterBuilder.Eq(x => x.device_name, GlobalSetting.ClientCode),
                                           filterBuilder.Eq(x => x.value, dataworkerKey));

            int count = _mongoDBHelper.DeleteMany<MongoDbTag>(GlobalSetting.MongoDbTime, filter);
            if (count > 0)
            {
                mongoDbTimeTag.ts = lastDatetime;
                _mongoDBHelper.InsertOne<MongoDbTag>(mongoDbTimeTag, GlobalSetting.MongoDbTime);
            }
        }
    }
}
